﻿using System;
using System.Collections.Generic;
using System.Globalization;
using Istace.Framework.Mapping.Core.Interfaces;
using Istace.Framework.Mapping.Core.Internal;

namespace Istace.Framework.Mapping.Core
{
    /// <summary>
    /// 
    /// </summary>
    public static class Repository
    {
        /// <summary>
        /// The repositories
        /// </summary>
        private static Dictionary<Type, IIndexedRepository> repositories;

        /// <summary>
        /// Gets the repository.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private static IIndexedRepository<T> GetRepository<T>()
        {
            if(repositories == null)
                repositories = new Dictionary<Type, IIndexedRepository>();

            if(!repositories.ContainsKey(typeof(T)))
            {
                repositories.Add(typeof(T), new InternalIndexedRepository<T>());
            }
            return repositories[typeof(T)] as IIndexedRepository<T>;
        }

        /// <summary>
        /// Try to get the object associated with the given index
        /// </summary>
        /// <param name="index">Index key used to identify the object</param>
        /// <param name="output">Object to retreive</param>
        /// <returns>True if the get succeed, Else false</returns>
        public static bool TryGetInstance<T>(string index, out T output)
        {
            return GetRepository<T>().TryGetInstance(index, out output);
        }

        /// <summary>
        /// GetInstance an indexed object based on the given key
        /// </summary>
        /// <param name="index">The key used to index the object</param>
        /// <returns>The stored instance</returns>
        public static T GetInstance<T>(string index)
        {
            return GetRepository<T>().GetInstance(index);
        }

        /// <summary>
        /// Try to add an object of T to the data dictionnary indexed on the given key 
        /// </summary>
        /// <param name="objectToAdd">The object to add indexed on key</param>
        /// <returns>True if</returns>
        public static bool TryAddInstance<T>(T objectToAdd)
        {
            return GetRepository<T>().TryAddInstance(objectToAdd.GetHashCode().ToString(CultureInfo.InvariantCulture), objectToAdd, false);
        }

        /// <summary>
        /// Try to add an object of T to the data dictionnary indexed on the given key 
        /// </summary>
        /// <param name="key">The key used to index the object within the repository</param>
        /// <param name="objectToAdd">The object to add indexed on key</param>
        /// <returns>True if</returns>
        public static bool TryAddInstance<T>(string key, T objectToAdd)
        {
            return GetRepository<T>().TryAddInstance(key, objectToAdd, false);
        }

        /// <summary>
        /// Try to add an object of T to the data dictionnary indexed on the given key 
        /// </summary>
        /// <param name="key">The key used to index the object within the repository</param>
        /// <param name="objectToAdd">The object to add indexed on key</param>
        /// <param name="replaceIfExist">If the object is already indexed, we will replace the existing instance</param>
        /// <returns>True if</returns>
        public static bool TryAddInstance<T>(string key, T objectToAdd, bool replaceIfExist)
        {
            return GetRepository<T>().TryAddInstance(key, objectToAdd, replaceIfExist);
        }

        /// <summary>
        /// AddInstance an object to the repository
        /// </summary>
        /// <param name="objectToAdd">The object to index</param>
        public static void AddInstance<T>(T objectToAdd)
        {
            GetRepository<T>().AddInstance(objectToAdd.GetHashCode().ToString(CultureInfo.InvariantCulture), objectToAdd, false);
        }

        /// <summary>
        /// AddInstance an object to the repository
        /// </summary>
        /// <param name="key">The key used to index the objectToAdd</param>
        /// <param name="objectToAdd">The object to index</param>
        public static void AddInstance<T>(string key, T objectToAdd)
        {
            GetRepository<T>().AddInstance(key, objectToAdd, false);
        }

        /// <summary>
        /// AddInstance an object to the repository
        /// </summary>
        /// <param name="key">The key used to index the objectToAdd</param>
        /// <param name="objectToAdd">The object to index</param>
        /// <param name="replaceIfExist">If true, if the object already exist, the existing instance is replaced by the new one</param>
        public static void AddInstance<T>(string key, T objectToAdd, bool replaceIfExist)
        {
            GetRepository<T>().AddInstance(key, objectToAdd, replaceIfExist);
        }
    }
}
